package cz.data.common.jackson;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.MissingNode;
import cz.data.common.core.DataGrantedAuthority;
import cz.data.common.core.DataRole;
import cz.data.common.core.DataUser;

import java.io.IOException;
import java.util.List;
import java.util.Set;

public class DataUserDeserializer extends JsonDeserializer<DataUser> {
    private static final TypeReference<Set<DataGrantedAuthority>> SIMPLE_GRANTED_AUTHORITY_SET = new TypeReference<Set<DataGrantedAuthority>>() {
    };
    private static final TypeReference<List<String>> SIMPLE_POSTS_LIST = new TypeReference<List<String>>() {
    };
    private static final TypeReference<List<DataRole>> SIMPLE_ROLES_LIST = new TypeReference<List<DataRole>>() {
    };

    @Override
    public DataUser deserialize(JsonParser jp, DeserializationContext deserializationContext) throws IOException, JacksonException {
        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        JsonNode jsonNode = mapper.readTree(jp);
        Set<DataGrantedAuthority> authorities = mapper.convertValue(jsonNode.get("authorities"), SIMPLE_GRANTED_AUTHORITY_SET);
        JsonNode passwordNode = this.readJsonNode(jsonNode, "password");
        String id = this.readJsonNode(jsonNode, "id").asText(null);
        String nickname = this.readJsonNode(jsonNode, "nickname").asText(null);
        String dept = this.readJsonNode(jsonNode, "dept").asText(null);
        String username = this.readJsonNode(jsonNode, "username").asText();
        String password = passwordNode.asText("");
        boolean enabled = this.readJsonNode(jsonNode, "enabled").asBoolean();
        boolean accountNonExpired = this.readJsonNode(jsonNode, "accountNonExpired").asBoolean();
        boolean credentialsNonExpired = this.readJsonNode(jsonNode, "credentialsNonExpired").asBoolean();
        boolean accountNonLocked = this.readJsonNode(jsonNode, "accountNonLocked").asBoolean();
        DataUser result = new DataUser(id, nickname, username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
        if (passwordNode.asText(null) == null) {
            result.eraseCredentials();
        }
        result.setDept(dept);
        List<String> posts = mapper.convertValue(jsonNode.get("posts"), SIMPLE_POSTS_LIST);
        result.setPosts(posts);
        List<DataRole> roles = mapper.convertValue(jsonNode.get("roles"), SIMPLE_ROLES_LIST);
        result.setRoles(roles);
        return result;
    }

    private JsonNode readJsonNode(JsonNode jsonNode, String field) {
        return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();
    }


}
